package sdk.webview.fmc.com.fmcsdk.service;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.PoiInfo;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import com.google.gson.Gson;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import sdk.webview.fmc.com.fmcsdk.R;
import sdk.webview.fmc.com.fmcsdk.base.BaseData;
import sdk.webview.fmc.com.fmcsdk.base.UserApi;
import sdk.webview.fmc.com.fmcsdk.bean.GPSBean;
import sdk.webview.fmc.com.fmcsdk.util.Constant;
import sdk.webview.fmc.com.fmcsdk.util.Url;
import sdk.webview.fmc.com.fmcsdk.util.UserHelper;
import sdk.webview.fmc.com.fmcsdk.util.Utility;
import sdk.webview.fmc.com.fmcsdk.util.XLog;
import sdk.webview.fmc.com.fmcsdk.util.retrofit2.observer.ApiFactory;

import static android.support.v4.app.NotificationCompat.PRIORITY_MIN;

/**
 * Created by ydm on 2018/8/27.
 */

public class LocationService extends Service {
    public static final String SUCCESS_STATUS = "200";//请求成功
    public static final String TOKEN_ERROR_STATUS = "401";//token失效
    private Context context;
    private String locationDescribe;
    private static BDLocation locations;
    private Gson gson;
    private GPSBean bean;
    private List<PoiInfo> poiList;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        context = this;
        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        //手机息屏时候唤醒CPU发送数据，不然过一会会中断
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LocationService.class.getName());
        wakeLock.acquire();
        //定位的间隔时间，分钟单位
        if (intent != null) {
            String locationTime = intent.getStringExtra("gpsTime");
            if (!TextUtils.isEmpty(locationTime)) {
                //开启定位
                startLocation(locationTime);
            }
        }


//        creatPushTongdao();

        String channelId = null;
        // 8.0 以上需要特殊处理
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            channelId = createNotificationChannel("kim.hsl", "ForegroundService");
        } else {
            channelId = "";
        }
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId);
        Notification notification = builder.setOngoing(true)
                .setPriority(PRIORITY_MIN)
                .setCategory(Notification.CATEGORY_SERVICE)
                .setContentTitle(context.getResources().getString(R.string.record_track))
                .setContentText(context.getResources().getString(R.string.gps_tips))
                .setSmallIcon(R.drawable.agreement_gray_shape)
                .setLargeIcon(getBitmap(context))
                .build();
        startForeground(1125, notification);


//
//        //创建标题栏
//        Notification noti = new Notification.Builder(this.getApplicationContext())//获取一个Notification构造器
//                .setContentTitle(context.getResources().getString(R.string.record_track))
//                .setContentText(context.getResources().getString(R.string.gps_tips))
//                .setSmallIcon(R.drawable.agreement_gray_shape)
//                .setLargeIcon(getBitmap(context))
//                .build();
//        startForeground(1125, noti);

        return super.onStartCommand(intent, Service.START_REDELIVER_INTENT, startId);

    }


    NotificationManager nm;

    /**
     * 极光/OPPO/FCM 通道通知实现
     */
    private void creatPushTongdao() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            if (nm != null) {
                NotificationChannelGroup notificationChannelGroup = new NotificationChannelGroup("gongdan", "工单任务相关");
                nm.createNotificationChannelGroup(notificationChannelGroup);

                createNotificationChannel("daiban", "待办", "android.resource://" + context.getPackageName() + "/raw/newtask");
                createNotificationChannel("qiangdan", "抢单", "android.resource://" + context.getPackageName() + "/raw/newgrab");
                createNotificationChannel("gonggao", "公告", "android.resource://" + context.getPackageName() + "/raw/msgnotify");
                createNotificationChannel("renwuguoqi", "工单任务过期", "android.resource://" + context.getPackageName() + "/raw/expire");
                createNotificationChannel("zhongyaoxinxi", "重要信息", "android.resource://" + context.getPackageName() + "/raw/important");
                createNotificationChannel("moren", "默认", "android.resource://" + context.getPackageName() + "/raw/msgnotify");
            }
        }
    }

    private void createNotificationChannel(String channel_id, String channelName, String soundUri) {
        NotificationChannel notificationChannel = new NotificationChannel(channel_id, channelName, NotificationManager.IMPORTANCE_HIGH);
        notificationChannel.setGroup("gongdan");
        notificationChannel.enableLights(true);
        notificationChannel.enableVibration(true);
        notificationChannel.setSound(Uri.parse(soundUri), null);

        nm.createNotificationChannel(notificationChannel);

    }


    /**
     * 创建通知通道
     *
     * @param channelId
     * @param channelName
     * @return
     */
    @RequiresApi(Build.VERSION_CODES.O)
    private String createNotificationChannel(String channelId, String channelName) {
        NotificationChannel chan = new NotificationChannel(channelId,
                channelName, NotificationManager.IMPORTANCE_NONE);
        chan.setLightColor(Color.BLUE);
        chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        service.createNotificationChannel(chan);
        return channelId;
    }


    private LocationClient mLocationClient;
    private SharedPreferences sharedPreferences;
    private PowerManager.WakeLock wakeLock;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //    private MyLocationListener myListener = new MyLocationListener();
    //开启定位
    private void startLocation(String gpsTime) {
        try {
            LocationClient.setAgreePrivacy(true);
            mLocationClient = new LocationClient(getApplicationContext());
            //声明LocationClient类
            mLocationClient.registerLocationListener(mListeners);
            LocationClientOption option = new LocationClientOption();

            //定位模式，目前为网络定位
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
            option.setOpenGps(false);// 打开gps
            option.setCoorType("bd09ll"); // 设置坐标类型
            option.setAddrType("all");
            //指定的时间定位一次
            option.setScanSpan(Integer.parseInt(gpsTime) * 60 * 1000);
//        option.setScanSpan(5000);
            mLocationClient.setLocOption(option);
            option.setIsNeedLocationDescribe(true);
            mLocationClient.start();


//            option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
//            //可选，设置定位模式，默认高精度
//            //LocationMode.Hight_Accuracy：高精度；
//            //LocationMode. Battery_Saving：低功耗；
//            //LocationMode. Device_Sensors：仅使用设备；
//            //LocationMode.Fuzzy_Locating, 模糊定位模式；v9.2.8版本开始支持，可以降低API的调用频率，但同时也会降低定位精度；
//
//            option.setCoorType("bd09ll");
//            //可选，设置返回经纬度坐标类型，默认gcj02
//            //gcj02：国测局坐标；
//            //bd09ll：百度经纬度坐标；
//            //bd09：百度墨卡托坐标；
//            //海外地区定位，无需设置坐标类型，统一返回wgs84类型坐标
//
//            option.setFirstLocType(LocationClientOption.FirstLocType.SPEED_IN_FIRST_LOC);
//            //可选，首次定位时可以选择定位的返回是准确性优先还是速度优先，默认为速度优先
//            //可以搭配setOnceLocation(Boolean isOnceLocation)单次定位接口使用，当设置为单次定位时，setFirstLocType接口中设置的类型即为单次定位使用的类型
//            //FirstLocType.SPEED_IN_FIRST_LOC:速度优先，首次定位时会降低定位准确性，提升定位速度；
//            //FirstLocType.ACCUARACY_IN_FIRST_LOC:准确性优先，首次定位时会降低速度，提升定位准确性；
//
////            option.setScanSpan(Integer.parseInt(gpsTime) * 60 * 1000);
//            option.setScanSpan(10000);
//            //可选，设置发起定位请求的间隔，int类型，单位ms
//            //如果设置为0，则代表单次定位，即仅定位一次，默认为0
//            //如果设置非0，需设置1000ms以上才有效
//
//            option.setOpenGnss(false);
//            //可选，设置是否使用卫星定位，默认false
//            //使用高精度和仅用设备两种定位模式的，参数必须设置为true
//
//            option.setLocationNotify(false);
//            //可选，设置是否当卫星定位有效时按照1S/1次频率输出卫星定位结果，默认false
//
//            option.setIgnoreKillProcess(true);
//            //可选，定位SDK内部是一个service，并放到了独立进程。
//            //设置是否在stop的时候杀死这个进程，默认（建议）不杀死，即setIgnoreKillProcess(true)
//
//            option.SetIgnoreCacheException(false);
//            //可选，设置是否收集Crash信息，默认收集，即参数为false
//
//            option.setWifiCacheTimeOut(5 * 60 * 1000);
//            //可选，V7.2版本新增能力
//            //如果设置了该接口，首次启动定位时，会先判断当前Wi-Fi是否超出有效期，若超出有效期，会先重新扫描Wi-Fi，然后定位
//
//            option.setEnableSimulateGnss(false);
//            //可选，设置是否需要过滤卫星定位仿真结果，默认需要，即参数为false
//
//            option.setNeedNewVersionRgc(true);
//            //可选，设置是否需要最新版本的地址信息。默认需要，即参数为true
//
//            mLocationClient.setLocOption(option);
//            //mLocationClient为第二步初始化过的LocationClient对象
//            //需将配置好的LocationClientOption对象，通过setLocOption方法传递给LocationClient对象使用
//            //更多LocationClientOption的配置，请参照类参考中LocationClientOption类的详细说明
//
//            mLocationClient.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*****
     *
     * 定位结果回调，重写onReceiveLocation方法，可以直接拷贝如下代码到自己工程中修改
     *
     */

    private BDAbstractLocationListener mListeners = new BDAbstractLocationListener() {

        @Override
        public void onReceiveLocation(BDLocation location) {
            XLog.i(location.toString() + ":=-=-=-=-");
            XLog.i(location.toString() + ":=-定位：=-=getLocType-=->" + location.getLocType());
            // TODO Auto-generated method stub
            if (null != location && location.getLocType() != BDLocation.TypeServerError) {
                locations = location;
                locationDescribe = location.getAddress().address;
                StringBuffer sb = new StringBuffer(256);
                sb.append("time : ");
                Log.e("shuchang", "locationDescribe--定位11：--->" + locationDescribe);
                getGeoAddress(location);

                /**
                 * 时间也可以使用systemClock.elapsedRealtime()方法 获取的是自从开机以来，每次回调的时间；
                 * location.getTime() 是指服务端出本次结果的时间，如果位置不发生变化，则时间不变
                 */
//                XLog.i(location.getTime(),LocationService.this);
//                sb.append("\nlocType : ");// 定位类型
//                sb.append(location.getLocType());
//                sb.append("\nlocType description : ");// *****对应的定位类型说明*****
//                sb.append(location.getLocTypeDescription());
                sb.append("\nlatitude : ");// 纬度
                sb.append(location.getLatitude());
                sb.append("\nlontitude : ");// 经度
                sb.append(location.getLongitude());
                if (location.getLongitude() == 0 || (location.getLongitude() + "").equals("0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049")) {
                    XLog.i("经纬度错误：" + location.getLatitude() + "--" + location.getLongitude() + "--" + location.getTime(), context);
                } else {  //发送心跳连接
                    sendHeartBeat(location.getLatitude(), location.getLongitude());
                    XLog.i("中海定位：" + Double.toString(location.getLatitude()) + "--" + Double.toString(location.getLongitude()) + "--!@");
                }

            } else {
//                ToastMgr.show("定位失败，请打开GPS或者检查网络");
                Log.e("LocationService", "定位失败，请打开GPS或者检查网络");
            }
        }

    };

    GeoCoder mCoder;
    LatLng mLatLng;

    private void getGeoAddress(BDLocation location) {
        mCoder = GeoCoder.newInstance();
        mLatLng = new LatLng(location.getLatitude(), location.getLongitude());
        mCoder.setOnGetGeoCodeResultListener(new OnGetGeoCoderResultListener() {

            @Override
            public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {

            }

            @Override
            public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
                if (reverseGeoCodeResult == null || reverseGeoCodeResult.error != SearchResult.ERRORNO.NO_ERROR) {
                    Log.e("shuchang", "locatinservice--->reverseGeoCodeResult.error-->" + reverseGeoCodeResult.error);
                    Log.e("shuchang", "locatinservice--->ReverseGeoCodeResult-->" + new Gson().toJson(reverseGeoCodeResult));
                    //没有找到检索结果
                    return;
                } else {
                    //详细地址
                    String address = reverseGeoCodeResult.getAddress();
                    poiList = reverseGeoCodeResult.getPoiList();
                    if (poiList != null && poiList.size() > 0) {
                        if (poiList.size() > 1) {
                            locationDescribe = locationDescribe + poiList.get(1).name + "附近";
                        } else {
                            locationDescribe = locationDescribe + poiList.get(0).name + "附近";
                        }
                    }

                    Log.e("shuchang", "locationDescribe--定位222：--->" + locationDescribe);
                    //行政区号
                    int adCode = reverseGeoCodeResult.getAdcode();

                    mCoder.destroy();
                }
            }
        });

        mCoder.reverseGeoCode(new ReverseGeoCodeOption()
                .location(mLatLng)
                // 设置是否返回新数据 默认值0不返回，1返回
                .newVersion(1)
                // POI召回半径，允许设置区间为0-1000米，超过1000米按1000米召回。默认值为1000
                .radius(50));
    }

    /**
     * 发送心跳接口
     */
    private void sendHeartBeat(final double lat, final double lon) {
        ApiFactory.getFactory().create(UserApi.class).sendHeartBeat(sharedPreferences.getString(Constant.BASE_ADDRESS_URL, "") + Url.SEND_HEARTBEAT, "XMLHttpRequest", UserHelper.getToken())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<BaseData>() {
                    @Override
                    public void onCompleted() {
//                        XLog.i("sendHeartBeat result：" + "onCompleted");
                    }

                    @Override
                    public void onError(Throwable e) {
//                        XLog.i("sendHeartBeat result：" + "onError:" + e,LocationService.this);
                    }

                    @Override
                    public void onNext(BaseData result) {//成功后向后台发送GPS数据
//                        XLog.i("sendHeartBeat sendGPS：" + result.getMessage() +"  Status:" +result.getStatus());
                        //如果成功了发送数据，如果是token过期跳转到登录界面
                        if (result.getStatus().equals(SUCCESS_STATUS)) {
                            sendGPS(lat, lon, result.getServerTime());
                        } else if (result.getStatus().equals(Url.TOKEN_ERROR_STATUS) || result.getStatus().equals(Url.TOKEN_FORBIDDEN)) {
                            XLog.i("定位token过期");
                            Utility.startLoginActivity(context);
                        }

                    }
                });

    }

    /**
     * 发送GPS定位信息
     *
     * @param lat  纬度
     * @param lon  经度
     * @param time 定位时间
     */
    private void sendGPS(final double lat, final double lon, String time) {
        if (gson == null) {
            gson = new Gson();
        }
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(Long.parseLong(time));
        String format = formatter.format(calendar.getTime());
        HashMap<String, Object> map = new HashMap<>();
        map.put("lat", lat + "");
        map.put("lon", lon + "");
        map.put("recordDate", format);
        map.put("gpsLocDesc", locationDescribe);
        XLog.i("经纬度：" + Double.toString(lat) + "--" + Double.toString(lon) + "--" + time + locationDescribe);
        //转为json数据发送，用raw方式传参。后台定义的
        String s1 = gson.toJson(map);
        RequestBody requestBody = RequestBody.create(MediaType.parse("raw"), s1);
        ApiFactory.getFactory().create(UserApi.class).sendRecordGps(sharedPreferences.getString(Constant.BASE_ADDRESS_URL, "") + Url.RECORD_GPS, Url.XMLHTTPREQUEST, UserHelper.getToken(), requestBody)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<BaseData>() {
                    @Override
                    public void onCompleted() {
//                        XLog.i( "sendGPS sendGPS：" + "onCompleted");
                    }

                    @Override
                    public void onError(Throwable e) {
//                        XLog.i( "sendGPS：" + "sendGPS onError:" + e,LocationService.this);
                    }

                    @Override
                    public void onNext(BaseData result) {
                        if (result.getStatus().equals(SUCCESS_STATUS)) {
                            if (bean == null) {
                                bean = new GPSBean();
                            }
                            bean.sLon = String.valueOf(lon);
                            bean.sLat = String.valueOf(lat);
                            bean.Position = locationDescribe;
                            String s = gson.toJson(bean);
                            sharedPreferences.edit().putString(Constant.LON_LAT_DESC, s).apply();
                        }
//                        XLog.i( "sendGPS sendGPS：" + result.getMessage() + result.getStatus());
                    }
                });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mLocationClient != null) {
            mLocationClient.unRegisterLocationListener(mListeners);
            mLocationClient.stop();
        }
        if (wakeLock != null) {
            wakeLock.release();
            wakeLock = null;
        }
        stopForeground(true);
        XLog.i("onDestroy", LocationService.this);
    }


    /**
     * 获取图标 bitmap
     *
     * @param context
     */
    public static synchronized Bitmap getBitmap(Context context) {
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
            packageManager = context.getApplicationContext()
                    .getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            applicationInfo = null;
        }
        Drawable d = packageManager.getApplicationIcon(applicationInfo); //xxx根据自己的情况获取drawable
        BitmapDrawable bd = (BitmapDrawable) d;
        Bitmap bm = bd.getBitmap();
        return bm;
    }


}
